package com.github.aloxc.plugin.restplus.action;

import com.github.aloxc.plugin.restplus.common.Consts;
import com.github.aloxc.plugin.restplus.common.DesUtil;
import com.github.aloxc.plugin.restplus.common.PsiAnnotationHelper;
import com.github.aloxc.plugin.restplus.i18n.I18Bundle;
import com.github.aloxc.plugin.restplus.listener.IRightClickHandler;
import com.github.aloxc.plugin.restplus.popup.PopupBalloon;
import com.github.aloxc.plugin.restplus.translate.TranslateService;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ThrowableRunnable;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;

import java.util.HashSet;
import java.util.Set;

/**
 * 右键swagger文档注释处理
 */
public class SwaggerAnnotationAction extends AbstractBaseAction implements IRightClickHandler {
    private TranslateService translatorService = ServiceManager.getService(TranslateService.class);
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        Project project = e.getData(LangDataKeys.PROJECT);
        if (project == null) {
            return;
        }
        Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
        PsiFile psiFile = e.getRequiredData(CommonDataKeys.PSI_FILE);
        //获取java文件
        PsiElement referenceAt = psiFile.findElementAt(editor.getCaretModel().getOffset());
        PsiJavaFile psiJavaFile = PsiTreeUtil.getParentOfType(referenceAt, PsiJavaFile.class);
        String path = psiFile.getVirtualFile().getPath();
        PsiElement[] allElement = psiJavaFile.getChildren();
        String check = checkSwaggerAnnotation(project,allElement);
        if(check != null){
            PopupBalloon.showPopupBalloon(editor,String.format(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.generateswagger.duplicate.text"),check),false);
            return;
        }
        PsiElementFactory factory = PsiElementFactory.SERVICE.getInstance(project);
        for (PsiElement everyTypeElement : allElement) {
            //判断是否import
            this.importClass(project, factory, everyTypeElement);
            //获取java正式内容
            if (!(everyTypeElement instanceof PsiClass)) {

                continue;
            }
            this.writeSwaggerAnnotation(project,factory,everyTypeElement);
            this.generateAnnotation(project, everyTypeElement);
            break;
        }
    }

    /**
     * 检查swagger的注解内容有无重复
     * @param project
     * @param allElement
     */
    private String checkSwaggerAnnotation(Project project,PsiElement[] allElement){
        Set<String> valueList = new HashSet<>();
        for (PsiElement everyTypeElement : allElement) {
            PsiElement[] clsEle = everyTypeElement.getChildren();
            for (PsiElement psiElement : clsEle) {
                if (!(psiElement instanceof PsiField)) {
                    continue;
                }
                PsiField psiField = (PsiField) psiElement;
                PsiAnnotation[] annotations = psiField.getAnnotations();
                String swaggerText = null;
                for (PsiAnnotation annotation : annotations) {
                    String qualifiedName = annotation.getQualifiedName();
                    if (Consts.Swagger.API_MODEL_PROPERTY.equals(qualifiedName)) {
                        //有注释的
//                        swaggerText = annotation.getParameterList().getAttributes()[0].getText();
//                        swaggerText = swaggerText.substring(1,swaggerText.length() - 1);
                        swaggerText = PsiAnnotationHelper.getAnnotationAttributeValue(annotation,"value");
                        if(valueList.contains(swaggerText)){
                            return swaggerText;
                        }else{
                            valueList.add(swaggerText);
                        }
                    }
                }
            }
        }
        return null;
    }
    /**
     * 生成字段的swagger注解
     *
     * @param project
     * @param everyTypeElement 具体的class代码element
     */
    private void generateAnnotation(Project project, PsiElement everyTypeElement) {
        PsiElement[] clsEle = everyTypeElement.getChildren();
        boolean hasSerialVersionUID = false;
        for (PsiElement psiElement : clsEle) {
            if (!(psiElement instanceof PsiField)) {
                continue;
            }
            PsiField psiField = (PsiField) psiElement;
            PsiDocComment docComment = psiField.getDocComment();
            String name = psiField.getName();
            boolean hasSwaggerAnnotation = false;
            PsiAnnotation[] annotations = psiField.getAnnotations();
            String swaggerText = null;
            if(name.equals("serialVersionUID")){
                hasSerialVersionUID = true;
            }
            for (PsiAnnotation annotation : annotations) {
                String qualifiedName = annotation.getQualifiedName();
                if (Consts.Swagger.API_MODEL_PROPERTY.equals(qualifiedName)) {
                    //已经有这个注解就跳过
                    hasSwaggerAnnotation = true;
//                    swaggerText = annotation.getAttributes().stream().filter(a->a.getAttributeName().equals("value")).map(a->a.getAttributeValue());
//                    swaggerText = annotation.getParameterList().getAttributes()[0].getText();
//                    swaggerText = swaggerText.substring(1,swaggerText.length() - 1);
                    swaggerText = PsiAnnotationHelper.getAnnotationAttributeValue(annotation,"value");
                    //把swagger的注解放到第一位
                    this.writeSwaggerAnnotation(project,psiElement,psiField,swaggerText,annotation);
                    continue;
                }
            }
            if (!hasSwaggerAnnotation) {
                //没有swagger注解，获取注释内容，生成注解
                if (docComment != null && StringUtils.isNotBlank(docComment.getText().trim())) {
                    PsiElement[] descriptionElements = docComment.getDescriptionElements();
                    for (PsiElement desc : descriptionElements) {
                        String text = desc.getText();
                        if (text != null && !"".equals(text.trim())) {
                            swaggerText = text;
                            this.writeSwaggerAnnotation(project, psiElement, psiField, text,null);
                        }
                    }
                } else {
                    // 获取单行注释的内容
                    String allText = psiField.getText();
                    String comment = "";
                    String[] split = allText.split("\n");
                    for (String s : split) {
                        if (s.contains("//")) {
                            comment = s.substring(s.indexOf("//") + 2, s.length() - 1);
                            continue;
                        }
                    }
                    if (StringUtils.isNotBlank(comment)) {
                        swaggerText = comment.trim();
                        this.writeSwaggerAnnotation(project, psiElement, psiField, comment.trim(),null);
                    } else {
                        String text = translatorService.translate(name);
                        if (StringUtils.isNotBlank(text)) {
                            swaggerText = text;
                            this.writeSwaggerAnnotation(project, psiElement, psiField, text,null);
                        }
                    }
                    if (StringUtils.isNotBlank(comment)) {
                        swaggerText = comment;
                        this.writeSwaggerAnnotation(project, psiElement, psiField, comment.trim(),null);
                    }
                }
            }else {

            }
            if(docComment == null){
                //没有字段注释，我们使用swagger的注释


            }
        }
    }

    /**
     * 添加swagger的ApiModel注解到java文件
     *
     * @param project
     * @param psiElement
     */
    private void writeSwaggerAnnotation(Project project,PsiElementFactory factory, PsiElement psiElement) {
        try {
            PsiClass psiClass = (PsiClass)psiElement;
            PsiAnnotation[] annotations = psiClass.getAnnotations();
            for (PsiAnnotation annotation : annotations) {
                String qualifiedName = annotation.getQualifiedName();
                if (Consts.Swagger.API_MODEL.equals(qualifiedName)) {
                    return;
                }
            }

            PsiDocComment docComment = psiClass.getDocComment();
            WriteCommandAction.writeCommandAction(project).run(
                    (ThrowableRunnable<Throwable>) () -> {
                        if (psiElement.getContainingFile() == null) {
                            return;
                        }
                        String desc = DesUtil.getDescription(psiClass);
                        if(desc == null || desc.trim().length() == 0){
                            desc = translatorService.translate(psiClass.getName());
                        }
                        // 写入注解
                        psiClass.getModifierList().addAnnotation(String.format("ApiModel(\"%s\")", desc));

                    });
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    /**
     * 注解写进java文件
     *
     * @param project
     * @param psiElement
     * @param psiField
     * @param text
     */
    private void writeSwaggerAnnotation(Project project, PsiElement psiElement, PsiField psiField, String text,PsiAnnotation annotation) {
        try {
            WriteCommandAction.writeCommandAction(project).run(
                    (ThrowableRunnable<Throwable>) () -> {
                        if (psiElement.getContainingFile() == null) {
                            return;
                        }
                        if(annotation != null){
                            annotation.delete();
                        }
                        if(psiField.getName().equals("serialVersionUID")) return;
                        // 写入注解
                        psiField.getModifierList().addAnnotation(String.format("ApiModelProperty(\"%s\")", text.trim()));

                    });
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    private void writeSerialVersionUID(Project project, PsiElement psiElement, PsiField psiField, String text) {
        try {
            WriteCommandAction.writeCommandAction(project).run(
                    (ThrowableRunnable<Throwable>) () -> {
                        if (psiElement.getContainingFile() == null) {
                            return;
                        }
                        // 写入注解
                        psiField.getModifierList();
//                        psiField.getModifierList().addAnnotation(String.format("ApiModelProperty(\"%s\")", text.trim()));

                    });
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    /**
     * 注释写进java文件
     *
     * @param project
     * @param psiElement
     * @param psiField
     * @param text
     */
    private void writeDocComment(Project project, PsiElement psiElement, PsiField psiField, String text) {
        try {
            WriteCommandAction.writeCommandAction(project).run(
                    (ThrowableRunnable<Throwable>) () -> {
                        if (psiElement.getContainingFile() == null) {
                            return;
                        }
                        // 写入注解
                        psiField.getModifierList();
//                        psiField.getModifierList().addAnnotation(String.format("ApiModelProperty(\"%s\")", text.trim()));

                    });
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
    /**
     * 导入class
     *
     * @param project
     * @param factory
     * @param child
     * @return boolean
     */
    private void importClass(Project project, PsiElementFactory factory, PsiElement child) {
        boolean wasImportSwagger = false;
        if (child instanceof PsiImportList) {
            PsiImportList psiImportList = (PsiImportList) child;
            PsiElement[] importList = child.getChildren();

            for (PsiElement importEle : importList) {
                if (importEle.getText().contains("io.swagger.annotations.*") ) {
                    wasImportSwagger = true;
                    break;
                }
            }
            if (!wasImportSwagger) {
                PsiImportStatement importStatement = factory.createImportStatementOnDemand("io.swagger.annotations");
                try {
                    WriteCommandAction.writeCommandAction(project).run(
                            (ThrowableRunnable<Throwable>) () -> {
                                if (child.getContainingFile() == null) {
                                    return;
                                }
                                // 写入import
                                psiImportList.add(importStatement);
                            });
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                }
            }
        }
    }

    @Override
    public void update(@NotNull AnActionEvent e) {
        PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE);
        FileType fileType = psiFile.getFileType();
        String name = fileType.getName();
        boolean visible = false;
        //TODO 先只支持java，kotlin的等以后再说
        if ("JAVA".equals(name)) {
            visible = true;
        }
        if (visible) {
            e.getPresentation().setText(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.generateswagger.text"));
            e.getPresentation().setDescription(I18Bundle.getMessage("com.github.aloxc.plugin.restplus.request.generateswagger.text"));
            e.getPresentation().setIcon(Consts.Icons.SWAGGER);
        }
        setActionPresentationVisible(e, visible);
    }
}
